package game.manager;

import game.Constants;
import game.Conversation;
import game.Event;
import game.Event.EventType;
import game.Message;
import game.Person;
import game.communication.Communication;
import game.manager.RelationshipManager.Relationship;
import game.util.Util;

import java.util.Date;
import java.util.List;
import java.util.Observable;
import java.util.Vector;

public class ConversationManager implements Manager {
	private List<Conversation> conversations;
	private List<Message> outbox;

	@Override
	public void gameUpdate() {
		final Date currentTime = new Date();
		final List<Message> ready = new Vector<Message>(this.outbox.size());

		for (Message message : this.outbox) {
			final Date messageTime = message.getTime();
			if (messageTime.compareTo(currentTime) <= 0) {
				// Queue the message to process
				ready.add(message);
			}
		}

		for (Message message : ready) {
			this.outbox.remove(message);
			this.processMessage(message);
		}
	}

	private void processMessage(Message message) {
		final Person sender = message.getSender();
		final Person receiver = message.getReceiver();
		final Conversation conversation = getConversation(sender, receiver);
		conversation.addMessage(message);

		if (!receiver.isUser()) {
			final Communication communication = message.getCommunication();
			final List<Communication> replies = communication.getReplies();

			if (!replies.isEmpty()) {
				final Communication reply = Util.GetRandomListValue(replies);

				final Date replyTime = getReplyTime(receiver, sender);
				if (replyTime != null)
					this.sendMessage(receiver, sender, reply, replyTime);
			}
		} else
			EventManager.getManager().sendEvent(
					new Event(EventType.NEW_MESSAGE));
	}

	/**
	 * Get's the time that a will reply to b
	 * 
	 * @param a
	 * @param b
	 * @return
	 */
	public Date getReplyTime(Person a, Person b) {
		final Date replyDate;
		final Relationship relationship = RelationshipManager.getManager()
				.getRelationship(a, b);
		final int strength = relationship.getStrength();

		long replyTime = Util.LinearInterpolate(Constants.REPLY_MAX,
				Constants.REPLY_MIN, Constants.RELATIONSHIP_MIN,
				Constants.RELATIONSHIP_MAX, strength);
		replyDate = Util.getFutureDate(replyTime);
		return replyDate;
	}

	public List<Conversation> getConversations() {
		return new Vector<Conversation>(this.conversations);
	}

	public Conversation getConversation(final Person aPerson, Person bPerson) {
		Conversation conversation = null;
		for (Conversation aConversation : conversations) {
			if (aConversation.isBetween(aPerson, bPerson))
				conversation = aConversation;
			break;
		}

		if (conversation == null) {
			conversation = new Conversation(aPerson, bPerson);
			this.conversations.add(conversation);
		}
		return conversation;
	}

	public void sendMessage(Person sender, Person receiver,
			Communication communication, Date timeToSend) {
		final Message message = new Message(sender, receiver, communication,
				timeToSend);

		outbox.add(message);
	}

	private static ConversationManager manager;

	public static ConversationManager getManager() {
		if (manager == null)
			manager = new ConversationManager();
		return manager;
	}

	private ConversationManager() {
		this.initialize();
	}

	@Override
	public void update(Observable o, Object arg) {
		final Event event = (Event) arg;

		switch (event.getType()) {
		case RESET:
			this.initialize();
			break;
		}
	}

	@Override
	public void initialize() {
		this.conversations = new Vector<Conversation>();
		this.outbox = new Vector<Message>();
	}
}
